#include <sstream>
#include <istream>
#include "G4RunManager.hh"
#include "G4UImanager.hh"
#include "G4VisExecutive.hh"
#include "G4UIExecutive.hh"
#include "QGSP_BERT.hh"
#include "Randomize.hh"
#include "TFile.h"
#include "KSimGlobals.hh"
#include "KSimDetectorConstruction.hh"
#include "KSimPrimaryGeneratorAction.hh"
#include "KSimRunAction.hh"
#include "KSimEventAction.hh"
#include "KSimSteppingAction.hh"
using namespace std;

void PrintUsage();

G4String dataFilePath;
G4String eventInterfaceFilePath;
int neutronCount;
G4String neutronPositionFilePath;
int maxNeutrons = 0;
int eventNum;
double neutronEnergy = 0;

int main(int argc, char** argv) {
	dataFilePath = "";
	eventInterfaceFilePath = "";
	neutronCount = 0; //*
	neutronPositionFilePath = "";
	eventNum = -1;
	bool startUI = false;

	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			if (argv[i][1] == 'h') {
				PrintUsage();
				return 0;
			} else if (argv[i][1] == 'c') {
				i++;
				neutronCount = atoi(argv[i]);
			} else if (argv[i][1] == 'o') {
				i++;
				dataFilePath = argv[i];
			} else if (argv[i][1] == 'e') {
				i++;
				eventInterfaceFilePath = argv[i];
			} else if (argv[i][1] == 'p') {
				i++;
				neutronPositionFilePath = argv[i];
			} else if (argv[i][1] == 'n') {
				i++;
				maxNeutrons = atoi(argv[i]);
			} else {
				PrintUsage();
				return 0;
			}
		} else {
			PrintUsage();
			return 0;
		}
	}

	bool proceed = true;

	if (neutronCount == 0) {
		G4cout << "Must enter a neutron count > 0\n";
		proceed = false;
	}
	if (dataFilePath == "") {
	 G4cout << "Must provide output file path\n";
	 proceed = false;
	}
//	if (eventInterfaceFilePath == "") {
//		G4cout << "Must provide event interface file path\n";
//		proceed = false;
//	}
//	if (neutronPositionFilePath == "") {
//		G4cout << "Must provide neutron position file path\n";
//		proceed = false;
//	}
//	if (maxNeutrons == 0) {
//		G4cout << "Must provide number of neutrons per decay > 0\n";
//		proceed = false;
//	}

	if (!proceed) {
		PrintUsage();
		return 0;
	}

	G4long myseed = 336028;
	CLHEP::HepRandom::setTheSeed(myseed);

	// Make the run manager (runningMan)
	G4RunManager *runningMan = new G4RunManager();

	// Instantiate and initialize user initialization classes
	KSimDetectorConstruction *construction = new KSimDetectorConstruction();
	runningMan->SetUserInitialization(construction);

	G4VUserPhysicsList *physics = new QGSP_BERT();
	runningMan->SetUserInitialization(physics);

	// Instantiate and initialize visualization manager
	G4VisManager *visMan = new G4VisExecutive();
	visMan->SetVerboseLevel(1);
	visMan->Initialize();

	// Instantiate and initialize user action classes
	KSimPrimaryGeneratorAction *generator = new KSimPrimaryGeneratorAction(neutronCount);
	runningMan->SetUserAction(generator);

	KSimRunAction *runAction = new KSimRunAction();
	runningMan->SetUserAction(runAction);

	KSimEventAction *eventAction = new KSimEventAction();
	runningMan->SetUserAction(eventAction);

	KSimSteppingAction* stepAction = new KSimSteppingAction();
	runningMan->SetUserAction(stepAction);

	// Initialize run manager
	runningMan->Initialize();

	TFile file(dataFilePath, "recreate");

	// Get pointer to UI manager and UI executive, then start session
	G4UImanager *UIman = G4UImanager::GetUIpointer();
	UIman->ApplyCommand("/run/verbose 0");
	UIman->ApplyCommand("/event/verbose 0");
	UIman->ApplyCommand("/tracking/verbose 0");
	if (startUI) {
		UIman->ApplyCommand("/vis/scene/create");
		UIman->ApplyCommand("/vis/scene/add/trajectories");
		UIman->ApplyCommand("/vis/open OGLIX");
		for (int i = 0; i < 1; i++) {
			UIman->ApplyCommand("/run/beamOn");
		}
		int argcFake = 0;
		G4UIExecutive *ui = new G4UIExecutive(argcFake, argv);
		ui->SessionStart();
		delete ui;
	} else {
		std::stringstream ss;
		ss << "/run/beamOn " << neutronCount /* * maxNeutrons*/;
		UIman->ApplyCommand(ss.str());
	}

	delete visMan;
	delete runningMan;

	file.Close();

	return 0;
}

void PrintUsage() {
	G4cout << "Usage:\n\t-c NeutronCount\n\t-o DataFilePath";
//				<< "\n\t-e EventInterfaceFilePath\n\t-p NeutronPositionFilePath";
}
